package xueqiu

import (
	"context"
	"fmt"
	"net/http"
	"strconv"
	"sync"

	"gitee.com/lyuanbo/stock-trade/internal/pkg/errorx"
	"gitee.com/lyuanbo/stock-trade/internal/pkg/stock/constant"
	"github.com/imroc/req/v3"
)

func (x *XueQiu) List() (items []constant.Stock, codeIds []string, err error) {
	resp, err := req.DefaultClient().R().SetCookies(&http.Cookie{Name: "xq_a_token", Value: x.token}, &http.Cookie{Name: "u", Value: generateCookieU()}).Get("https://stock.xueqiu.com/v5/stock/portfolio/stock/list.json?size=10000&category=1&pid=-1")
	if err != nil {
		return nil, nil, errorx.New("雪球API->持仓列表", err)
	}

	var result listResponse
	err = resp.UnmarshalJson(&result)
	if err != nil {
		return nil, nil, errorx.New("雪球API->持仓列表->UnmarshalJson", err)
	}

	if result.ErrorCode != float64(0) {
		// result.ErrorCode 非 0 说明请求失败
		switch result.ErrorCode.(type) {
		case int:
		}

		code, _ := strconv.ParseInt(result.ErrorCode.(string), 10, 64)
		return nil, nil, errorx.WithCode(int(code), "雪球API->持仓列表->请求错误", fmt.Errorf("错误码: %s，描述: %s", result.ErrorCode, result.ErrorDescription))
	}

	// 转换成 constant.Stock
	var mux sync.Mutex
	var wg sync.WaitGroup
	for _, s := range result.Data.Stocks {
		wg.Add(1)
		go func() {
			defer wg.Done()

			typ := x.listByType(s.Type)

			var item constant.Stock
			// 处理沪/深股代码
			code := s.Symbol
			if s.Exchange == constant.ExchangeTypeSH || s.Exchange == constant.ExchangeTypeSZ {
				code = s.Symbol[len(s.Exchange):]

				// 获取精度
				stock, _ := x.Info(context.TODO(), fmt.Sprintf("%s%s", s.Exchange, code))
				item.Precision = stock.Precision
			}

			item.Code = code
			item.Name = s.Name
			item.Type = typ
			item.Exchange = constant.ExchangeType(s.Exchange)

			mux.Lock()
			items = append(items, item)
			mux.Unlock()
		}()
	}

	wg.Wait()
	return items, x.toCodeIds(items), nil
}

func (x *XueQiu) listByType(typ int) constant.StockType {
	switch typ {
	case 4:
		return constant.StockTypeNASDAQ // 美股
	case 11:
		return constant.StockTypeStock // 股票
	case 12:
		return constant.StockTypeIndex // 行业
	case 13:
		return constant.StockTypeETF // ETF
	case 30:
		return constant.StockTypeHKStock // 港股
	case 31:
		return constant.StockTypeHKIndex // 港股指数
	default:
		return constant.StockTypeNone // 其他
	}
}

// []constant.Stock 转 []string
func (x *XueQiu) toCodeIds(codes []constant.Stock) []string {
	var codeIds []string
	for _, code := range codes {
		codeIds = append(codeIds, fmt.Sprintf("%s%s", code.Exchange, code.Code)) // sh => SH
	}
	return codeIds
}
